#include "stdafx.h"
#include "MLMovStreamCommander.h"
#include "MLConsolePrinter.h"

#include "MLClustering_BIRCH.h"

#include "MLNumGen_Normal.h"
#include "MLNumGen_Uniform.h"

#include "MLTools_DistributionGenerator.h"
#include "MLTools_TxtFileLoader.h"
#include "MLTools_TxtFileSaver.h"

#include "MLDataSet.h"
#include "MLTools.h"
#include "MLTools_Stat.h"

#include "MLConsoleCluStream.h"
#include "MLConsoleMovStream.h"

CMLMovStreamCommander::CMLMovStreamCommander(void)
{
}

CMLMovStreamCommander::~CMLMovStreamCommander(void)
{
}

int CMLMovStreamCommander::Run(const std::vector<std::wstring>& vCommand)
{
	if(_wcsicmp(vCommand[0].c_str(), L"clustream") == 0)
	{
		return RunCluStream(vCommand);
	}
	else if(_wcsicmp(vCommand[0].c_str(), L"clumovstream") == 0)
	{
		return RunMovStream(vCommand);
	}
	else if(_wcsicmp(vCommand[0].c_str(), L"datastreamtrack") == 0)
	{
		return RunMovStream(vCommand);
	}
	else if(_wcsicmp(vCommand[0].c_str(), L"datasetgenerate") == 0)
	{
		return RunGenerateDataSet(vCommand);
	}
	else if(_wcsicmp(vCommand[0].c_str(), L"distributiongenerate") == 0)
	{
		return RunTestDataSetDistribution(vCommand);
	}
	else
	{
		_ASSERT(false);
	}
	return -1;
}

int CMLMovStreamCommander::RunCluStream(const std::vector<std::wstring> &vCommand)
{
	CMLConsoleCluStream consoleCluStream;
	return consoleCluStream.Run(vCommand);
}

int CMLMovStreamCommander::RunMovStream(const std::vector<std::wstring> &vCommand)
{
	CMLConsoleMovStream consoleMovStream;
	return consoleMovStream.Run(vCommand);
}

int CMLMovStreamCommander::RunGenerateDataSet(const std::vector<std::wstring>& vCommand)
{
	int nRet;
	if (vCommand.size() < 6)
	{
		_ASSERT(false);
		return -1;
	}
	int nComIndex = 1;
	std::wstring wstrAppend         = vCommand[nComIndex++];
	std::wstring wstrOutputFileName = vCommand[nComIndex++];
	std::wstring wstrCount          = vCommand[nComIndex++];
	std::wstring wstrDimensions     = vCommand[nComIndex++];
	int nDataCount  = _wtoi(wstrCount.c_str());
	int nDimensions = _wtoi(wstrDimensions.c_str());

	bool bAppendSave = false;
	if (_wcsicmp(wstrAppend.c_str(), L"append") == 0)
		bAppendSave = true;

	mylablib::CMLDataSet dataSet;
	mylablib::CMLTools_TxtFileSaver txtFileSaver;

	// Reset the seed of random generator
	mylablib::CMLNumGen_Uniform::ResetSeed();
	
	std::vector<mylablib::IMLRandomNumberGenerator*> vMixedGens;
	while (nComIndex < (int)vCommand.size())
	{
		std::wstring wstrDistributionName  = vCommand[nComIndex++];
		mylablib::IMLRandomNumberGenerator* pGen = NULL;

		if (_wcsicmp(wstrDistributionName.c_str(), L"normal") == 0)
		{
			std::vector<double> vMean;
			std::vector<double> vVariance;
			vMean.resize((size_t)nDimensions);
			vVariance.resize((size_t)nDimensions);
			int d;
			for (d=0; d<nDimensions; d++)
			{
				if ((int)vCommand.size() >= nComIndex + 2)
				{
					vMean[d] = _wtof(vCommand[nComIndex++].c_str());
					vVariance[d] = _wtof(vCommand[nComIndex++].c_str());
				}
			}

			pGen = new mylablib::CMLNumGen_Normal(vMean, vVariance);
		}
		else if (_wcsicmp(wstrDistributionName.c_str(), L"uniform") == 0)
		{
			std::vector<double> vMin;
			std::vector<double> vMax;
			vMin.resize((size_t)nDimensions);
			vMax.resize((size_t)nDimensions);
			int d;
			for (d=0; d<nDimensions; d++)
			{
				if ((int)vCommand.size() >= nComIndex + 2)
				{
					vMin[d] = _wtof(vCommand[nComIndex++].c_str());
					vMax[d] = _wtof(vCommand[nComIndex++].c_str());
				}
			}
			pGen = new mylablib::CMLNumGen_Uniform(vMin, vMax);
		}
		else
		{
			_ASSERT(false);
			return -1;
		}
		vMixedGens.push_back(pGen);
	}
	int i;
	int nGenIndex = 0;
	dataSet.Resize(nDataCount);
	for (i=0; i<nDataCount; i++)
	{
		mylablib::IMLRandomNumberGenerator* pGen = vMixedGens[nGenIndex];
		dataSet.Set(i, pGen->Generate());
		nGenIndex++;
		if (nGenIndex >= (int)vMixedGens.size())
			nGenIndex = 0;
	}

	nRet = txtFileSaver.Initialize(wstrOutputFileName, bAppendSave);
	ML_ON_FAILED_RETURN(nRet);

	nRet = txtFileSaver.Save(dataSet);
	ML_ON_FAILED_RETURN(nRet);

	txtFileSaver.Close();
	for (i=0; i<(int)vMixedGens.size(); i++)
	{
		delete vMixedGens[i];
	}
	return 0;
}

int CMLMovStreamCommander::RunTestDataSetDistribution(const std::vector<std::wstring>& vCommand)
{
	int nRet;
	if (vCommand.size() < 4)
	{
		_ASSERT(false);
		return -1;
	}
	std::wstring wstrInputFileName     = vCommand[1];
	std::wstring wstrOutputFileName    = vCommand[2];
	std::wstring wstrNumBucket         = vCommand[3];
	mylablib::CMLDataSet dataSet;
	mylablib::CMLTools_DistributionGenerator distributionGen;

	// Load the input dataset
	mylablib::CMLTools_TxtFileLoader txtLoader;
	nRet = txtLoader.Initialize(wstrInputFileName);
	if (ML_FAILED(nRet))
	{
		CMLConsolePrinter::PrintError(L"Cannot open the input dataset file : %s\n", wstrInputFileName.c_str());
		_ASSERT(false);
		return nRet;
	}
	nRet = txtLoader.Load(dataSet);
	if (ML_FAILED(nRet))
	{
		CMLConsolePrinter::PrintError(L"Cannot read the input dataset file : %s\n", wstrInputFileName.c_str());
		_ASSERT(false);
		return nRet;
	}
	txtLoader.Close();

	// Initialize the distribution generator
	int nNumBucket = _wtoi(wstrNumBucket.c_str());
	distributionGen.Initialize(nNumBucket);

	// Scan the distributions
	mylablib::CMLDataSet probs;
	nRet = distributionGen.Generate(dataSet, probs);
	ML_ON_FAILED_RETURN(nRet);

	// Output the distributions
	mylablib::CMLTools_TxtFileSaver txtFileSaver;
	nRet = txtFileSaver.Initialize(wstrOutputFileName);
	ML_ON_FAILED_RETURN(nRet);

	nRet = txtFileSaver.Save(probs);
	ML_ON_FAILED_RETURN(nRet);

	txtFileSaver.Close();

	return 0;
}
